`include "defines.v"

module cpu(
    input                                   clock,
    input                                   reset,

    output wire[`RAM_ADDR_WIDTH - 1:0]      iram_addr,
    input  wire[`IRAM_DATA_WIDTH - 1:0]     iram_rdata,

    output wire                             iram_valid,
    input  wire                             iram_ready,

    output wire                             dram_wen,
    output wire[`RAM_ADDR_WIDTH - 1:0]      dram_addr,
    output wire[`RAM_DATA_WIDTH - 1:0]      dram_wdata,
    output wire[`RAM_DATA_WIDTH / 8 - 1:0]  dram_wmask,
    input  wire[`RAM_DATA_WIDTH - 1:0]      dram_rdata,
    output wire[2:0]                        dram_rw_size,

    output wire                             dram_valid,
    input  wire                             dram_ready
);


    // Definition
    // ctrl
    wire[4:0]                           ctrl_stall_o;
    wire[3:0]                           ctrl_flush_o;
    // if stage
    wire [`RAM_ADDR_WIDTH - 1:0]        if_inst_addr_o;
    wire [`INST_WIDTH - 1: 0]           if_inst_o;
    wire                                stall_pc_flag_o;
    wire                                flush_if_id_flag_o;
    // id stage
    wire [`RAM_ADDR_WIDTH - 1:0]        id_inst_addr_i;
    wire [`INST_WIDTH - 1: 0]           id_inst_i;

    wire [`REG_BUS]                     id_csr_r_data_i;

    wire                                id_csr_r_ena_o;
    wire [11: 0]                        id_csr_r_addr_o;

    wire [`REG_BUS]                     id_rs1_r_data_i;
    wire [`REG_BUS]                     id_rs2_r_data_i;

    wire                                id_rs1_r_ena_o;
    wire [4 : 0]                        id_rs1_r_addr_o;
    wire                                id_rs2_r_ena_o;
    wire [4 : 0]                        id_rs2_r_addr_o;

    wire [`RAM_ADDR_WIDTH - 1:0]        id_inst_addr_o;
    wire [`INST_WIDTH - 1: 0]           id_inst_o;

    wire                                id_rd_w_ena_o;
    wire [4 : 0]                        id_rd_w_addr_o;

    wire                                id_csr_w_ena_o;
    wire [11: 0]                        id_csr_w_addr_o;

    wire [`REG_BUS]                     id_op1_o;
    wire [`REG_BUS]                     id_op2_o;
    wire [`REG_BUS]                     id_op3_o;

    wire[`ALU_SEL_BUS]                  id_alu_sel_o;
    wire                                id_alu_sub_flag_o;
    wire                                id_alu_word_flag_o;
    wire                                id_alu_symbol_flag_o;

    wire                                id_transfer_en_o;
    wire[`TRANSFER_SEL_BUS]             id_transfer_sel_o;

    wire                                id_mem_load_en_o;
    wire                                id_mem_store_en_o;
    wire[`MEM_SEL_BUS]                  id_mem_sel_o;

    // wire                                id_csr_en_o;
    wire[`CSR_SEL_BUS]                  id_csr_sel_o;

    wire[`RD_SEL_BUS]                   id_rd_sel_o;

    wire [`REG_BUS]                     id_exception_type_o;

    wire                                id_valid_o;
    wire                                id_stall_flag_o;
    //exe stage

    wire [`RAM_ADDR_WIDTH - 1:0]        exe_inst_addr_i;
    wire [`INST_WIDTH - 1: 0]           exe_inst_i;

    wire                                exe_csr_w_ena_i;
    wire [11: 0]                        exe_csr_w_addr_i;

    wire                                exe_rd_w_ena_i;
    wire [4 : 0]                        exe_rd_w_addr_i;

    wire [`REG_BUS]                     exe_op1_i;
    wire [`REG_BUS]                     exe_op2_i;
    wire [`REG_BUS]                     exe_op3_i;

    wire[`ALU_SEL_BUS]                  exe_alu_sel_i;
    wire                                exe_alu_sub_flag_i;
    wire                                exe_alu_word_flag_i;
    wire                                exe_alu_symbol_flag_i;

    wire                                exe_transfer_en_i;
    wire[`TRANSFER_SEL_BUS]             exe_transfer_sel_i;

    // wire                                exe_csr_en_i;
    wire[`CSR_SEL_BUS]                  exe_csr_sel_i;

    wire                                exe_mem_load_en_i;
    wire                                exe_mem_store_en_i;
    wire[`MEM_SEL_BUS]                  exe_mem_sel_i;

    wire[`RD_SEL_BUS]                   exe_rd_sel_i;

    wire [`REG_BUS]                     exe_exception_type_i;
    wire                                exe_valid_i;

    wire [`RAM_ADDR_WIDTH - 1:0]        exe_inst_addr_o;
    wire [`INST_WIDTH - 1: 0]           exe_inst_o;

    wire                                exe_csr_w_ena_o;
    wire [11: 0]                        exe_csr_w_addr_o;
    wire [`REG_BUS]                     exe_csr_w_data_o;

    wire                                exe_rd_w_ena_o;
    wire [4 : 0]                        exe_rd_w_addr_o;
    wire [`REG_BUS]                     exe_rd_w_data_o;

    wire [`RAM_ADDR_WIDTH - 1:0]        exe_mem_addr_o;
    wire [`RAM_DATA_WIDTH - 1:0]        exe_mem_w_data_o;

    wire                                exe_transfer_flag_o;
    wire [`RAM_ADDR_WIDTH - 1:0]        exe_transfer_addr_o;


    wire                                exe_mem_load_en_o;
    wire                                exe_mem_store_en_o;
    wire[`MEM_SEL_BUS]                  exe_mem_sel_o;

    wire [`REG_BUS]                     exe_exception_type_o;
    wire                                exe_valid_o;
    //mem stage
 
    wire [`RAM_ADDR_WIDTH - 1:0]        mem_inst_addr_i;
    wire [`INST_WIDTH - 1: 0]           mem_inst_i;

    wire                                mem_csr_w_ena_i;
    wire [11: 0]                        mem_csr_w_addr_i;
    wire [`REG_BUS]                     mem_csr_w_data_i;

    wire                                mem_rd_w_ena_i;
    wire [4 : 0]                        mem_rd_w_addr_i;
    wire [`REG_BUS]                     mem_rd_w_data_i;

    wire [`RAM_ADDR_WIDTH - 1:0]        mem_mem_addr_i;
    wire [`RAM_DATA_WIDTH - 1:0]        mem_mem_w_data_i;

    wire [`RAM_DATA_WIDTH - 1:0]        mem_mem_r_data_i;

    wire                                mem_mem_load_en_i;
    wire                                mem_mem_store_en_i;
    wire[`MEM_SEL_BUS]                  mem_mem_sel_i;

    wire [`REG_BUS]                     mem_exception_type_i;
    wire                                mem_valid_i;

    wire [`RAM_ADDR_WIDTH - 1:0]        mem_inst_addr_o;
    wire [`INST_WIDTH - 1: 0]           mem_inst_o;

    wire                                mem_csr_w_ena_o;
    wire [11: 0]                        mem_csr_w_addr_o;
    wire [`REG_BUS]                     mem_csr_w_data_o;

    wire                                mem_rd_w_ena_o;
    wire [ 4: 0]                        mem_rd_w_addr_o;
    wire [`REG_BUS]                     mem_rd_w_data_o;
    
    wire [`RAM_DATA_WIDTH / 8 - 1:0]    mem_dram_w_mask_o;
    wire [`RAM_DATA_WIDTH - 1:0]        mem_dram_w_data_o;
    wire                                mem_dram_w_en_o;
    wire [`RAM_ADDR_WIDTH - 1:0]        mem_dram_addr_o;
    wire [2:0]                          mem_dram_rw_size_o;

    wire                                mem_dram_valid;
    wire                                mem_dram_ready;

    wire                                mem_stall_3_2_1_flag_o;

    wire [`REG_BUS]                     mem_exception_type_o;
    wire                                mem_valid_o;
    wire                                mem_skip_o;
    //wb stage
    wire [`RAM_ADDR_WIDTH - 1:0]        wb_inst_addr_i;
    wire [`INST_WIDTH - 1: 0]           wb_inst_i;

    wire                                wb_csr_w_ena_i;
    wire [11: 0]                        wb_csr_w_addr_i;
    wire [`REG_BUS]                     wb_csr_w_data_i;

    wire                                wb_rd_w_ena_i;
    wire [4 : 0]                        wb_rd_w_addr_i;
    wire [`REG_BUS]                     wb_rd_w_data_i;

    wire [`REG_BUS]                     wb_exception_type_i;
    wire                                wb_valid_i;

    wire                                wb_skip_i;

    wire [`RAM_ADDR_WIDTH - 1:0]        wb_inst_addr_o;
    wire [`INST_WIDTH - 1: 0]           wb_inst_o;

    wire                                wb_csr_w_ena_o;
    wire [11: 0]                        wb_csr_w_addr_o;
    wire [`REG_BUS]                     wb_csr_w_data_o;

    wire                                wb_rd_w_ena_o;
    wire [4 : 0]                        wb_rd_w_addr_o;
    wire [`REG_BUS]                     wb_rd_w_data_o;

    wire [`REG_BUS]                     wb_exception_type_o;
    wire                                wb_valid_o;

    wire                                wb_skip_o;
    //csr
    wire                                csr_transfer_flag_o;
    wire [`RAM_ADDR_WIDTH - 1:0]        csr_transfer_addr_o;

    wire                                csr_timer_interrupt_flag_o;

    //clint
    wire                                clint_timer_interrupt_o;
    //DifftestInstrCommit
    reg [ 7:0] coreid_sim;
    reg [ 7:0] index_sim;
    reg        valid_sim;
    reg [63:0] pc_sim;
    reg [31:0] instr_sim;
    reg        skip_sim;
    reg        isRVC_sim;
    reg        scFailed_sim;
    reg        wen_sim;
    reg [ 7:0] wdest_sim;
    reg [63:0] wdata_sim;

    // DifftestArchEvent
    reg [63:0] exception_code;
    wire[63:0] exception_code_wire;
    // DifftestCSRState
    wire[`REG_BUS]                      mstatus_diff;
    wire[`REG_BUS]                      sstatus_diff;
    wire[`REG_BUS]                      mepc_diff;
    wire[`REG_BUS]                      mtvec_diff;
    wire[`REG_BUS]                      mcause_diff;
    wire[`REG_BUS]                      mip_diff;
    wire[`REG_BUS]                      mie_diff;
    wire[`REG_BUS]                      mscratch_diff;    
/////////////////////////////////////////////////////////////////////////////////////////////////////
    //ctrl
    ctrl Ctrl(

        .stall_pc_flag_i        (stall_pc_flag_o),

        .flush_if_id_flag_i     (flush_if_id_flag_o),

        .stall_flag_from_id_i   (id_stall_flag_o),

        .flush_flag_from_exe_i  (exe_transfer_flag_o),

        .stall_3_2_1_flag_i     (mem_stall_3_2_1_flag_o),

        .csr_transfer_flag_i    (csr_transfer_flag_o),

        .stall_o                (ctrl_stall_o),
        .flush_o                (ctrl_flush_o)
    );
    //if_stage

    if_stage If_stage(
        .clk                    (clock),
        .rst                    (reset),

        .stall_i                (ctrl_stall_o[4]),

        .transfer_flag_i        (exe_transfer_flag_o),
        .transfer_addr_i        (exe_transfer_addr_o),

        .exception_flag_i       (csr_transfer_flag_o),
        .exception_addr_i       (csr_transfer_addr_o),

        .iram_addr              (iram_addr),
        .iram_rdata             (iram_rdata),
        .iram_valid             (iram_valid),
        .iram_ready             (iram_ready),

        .stall_pc_flag_o        (stall_pc_flag_o),

        .flush_if_id_flag_o     (flush_if_id_flag_o),

        .inst_addr              (if_inst_addr_o),
        .inst                   (if_inst_o)
    );

    if_id If_id(
        .clk                    (clock),
        .rst                    (reset),

        .stall_i                (ctrl_stall_o[3]),
        .flush_i                (ctrl_flush_o[3]),

        .inst_addr_i            (if_inst_addr_o),
        .inst_i                 (if_inst_o),

        .inst_addr_o            (id_inst_addr_i),
        .inst_o                 (id_inst_i)
    );
    // id_stage
    id_stage Id_stage(
        .timer_interrupt_flag_i (csr_timer_interrupt_flag_o),

        .inst_addr_i            (id_inst_addr_i),
        .inst_i                 (id_inst_i),
        
        .exe_csr_w_addr_i       (exe_csr_w_addr_o),
        .exe_csr_w_data_i       (exe_csr_w_data_o),
        .exe_csr_w_ena_i        (exe_csr_w_ena_o),

        .mem_csr_w_addr_i       (mem_csr_w_addr_o),
        .mem_csr_w_data_i       (mem_csr_w_data_o),
        .mem_csr_w_ena_i        (mem_csr_w_ena_o),

        .wb_csr_w_addr_i        (wb_csr_w_addr_o),
        .wb_csr_w_data_i        (wb_csr_w_data_o),
        .wb_csr_w_ena_i         (wb_csr_w_ena_o),

        .csr_r_data_i           (id_csr_r_data_i),
        .csr_r_ena_o            (id_csr_r_ena_o),
        .csr_r_addr_o           (id_csr_r_addr_o),

        .exe_mem_load_en_i      (exe_mem_load_en_o),

        .exe_rd_w_ena_i         (exe_rd_w_ena_o),
        .exe_rd_w_addr_i        (exe_rd_w_addr_o),
        .exe_rd_w_data_i        (exe_rd_w_data_o),

        .mem_rd_w_ena_i         (mem_rd_w_ena_o),
        .mem_rd_w_addr_i        (mem_rd_w_addr_o),
        .mem_rd_w_data_i        (mem_rd_w_data_o),

        .wb_rd_w_ena_i          (wb_rd_w_ena_o),
        .wb_rd_w_addr_i         (wb_rd_w_addr_o),
        .wb_rd_w_data_i         (wb_rd_w_data_o),

        .rs1_r_data_i           (id_rs1_r_data_i),
        .rs2_r_data_i           (id_rs2_r_data_i),

        .rs1_r_ena_o            (id_rs1_r_ena_o),
        .rs1_r_addr_o           (id_rs1_r_addr_o),
        .rs2_r_ena_o            (id_rs2_r_ena_o),
        .rs2_r_addr_o           (id_rs2_r_addr_o),

        .inst_addr_o            (id_inst_addr_o),
        .inst_o                 (id_inst_o),

        .csr_w_ena_o            (id_csr_w_ena_o),
        .csr_w_addr_o           (id_csr_w_addr_o),
        .rd_w_ena_o             (id_rd_w_ena_o),
        .rd_w_addr_o            (id_rd_w_addr_o),
        .op1_o                  (id_op1_o),
        .op2_o                  (id_op2_o),
        .op3_o                  (id_op3_o),

        .alu_sel_o              (id_alu_sel_o),
        .alu_sub_flag_o         (id_alu_sub_flag_o),
        .alu_word_flag_o        (id_alu_word_flag_o),
        .alu_symbol_flag_o      (id_alu_symbol_flag_o),

        .transfer_en_o          (id_transfer_en_o),
        .transfer_sel_o         (id_transfer_sel_o),

        .mem_load_en_o          (id_mem_load_en_o),
        .mem_store_en_o         (id_mem_store_en_o),
        .mem_sel_o              (id_mem_sel_o),

        // .csr_en_o               (id_csr_en_o),
        .csr_sel_o              (id_csr_sel_o),

        .rd_sel_o               (id_rd_sel_o),

        .exception_type_o       (id_exception_type_o),
        .valid_o                (id_valid_o),
        .stall_flag_o           (id_stall_flag_o)
    );
    id_exe Id_exe(
        .clk                    (clock),
        .rst                    (reset),

        .stall_i                (ctrl_stall_o[2]),
        .flush_i                (ctrl_flush_o[2]),

        .inst_addr_i            (id_inst_addr_o),
        .inst_i                 (id_inst_o),

        .csr_w_ena_i            (id_csr_w_ena_o),
        .csr_w_addr_i           (id_csr_w_addr_o),

        .rd_w_ena_i             (id_rd_w_ena_o),
        .rd_w_addr_i            (id_rd_w_addr_o),

        .op1_i                  (id_op1_o),
        .op2_i                  (id_op2_o),
        .op3_i                  (id_op3_o),

        .alu_sel_i              (id_alu_sel_o),
        .alu_sub_flag_i         (id_alu_sub_flag_o),
        .alu_word_flag_i        (id_alu_word_flag_o),
        .alu_symbol_flag_i      (id_alu_symbol_flag_o),

        .transfer_en_i          (id_transfer_en_o),
        .transfer_sel_i         (id_transfer_sel_o),

        // .csr_en_i               (id_csr_en_o),
        .csr_sel_i              (id_csr_sel_o),

        .mem_load_en_i          (id_mem_load_en_o),
        .mem_store_en_i         (id_mem_store_en_o),
        .mem_sel_i              (id_mem_sel_o),

        .rd_sel_i               (id_rd_sel_o),

        .exception_type_i       (id_exception_type_o),
        .valid_i                (id_valid_o),

        .inst_addr_o            (exe_inst_addr_i),
        .inst_o                 (exe_inst_i),

        .csr_w_ena_o            (exe_csr_w_ena_i),
        .csr_w_addr_o           (exe_csr_w_addr_i),

        .rd_w_ena_o             (exe_rd_w_ena_i),
        .rd_w_addr_o            (exe_rd_w_addr_i),

        .op1_o                  (exe_op1_i),
        .op2_o                  (exe_op2_i),
        .op3_o                  (exe_op3_i),

        .alu_sel_o              (exe_alu_sel_i),
        .alu_sub_flag_o         (exe_alu_sub_flag_i),
        .alu_word_flag_o        (exe_alu_word_flag_i),
        .alu_symbol_flag_o      (exe_alu_symbol_flag_i),

        .transfer_en_o          (exe_transfer_en_i),
        .transfer_sel_o         (exe_transfer_sel_i),

        // .csr_en_o               (exe_csr_en_i),
        .csr_sel_o              (exe_csr_sel_i),

        .mem_load_en_o          (exe_mem_load_en_i),
        .mem_store_en_o         (exe_mem_store_en_i),
        .mem_sel_o              (exe_mem_sel_i),

        .rd_sel_o               (exe_rd_sel_i),

        .exception_type_o       (exe_exception_type_i),
        .valid_o                (exe_valid_i)
    );
    // exe_stage
    
    exe_stage Exe_stage(
        .inst_addr_i            (exe_inst_addr_i),
        .inst_i                 (exe_inst_i),

        .csr_w_ena_i            (exe_csr_w_ena_i),
        .csr_w_addr_i           (exe_csr_w_addr_i),

        .rd_w_ena_i             (exe_rd_w_ena_i),
        .rd_w_addr_i            (exe_rd_w_addr_i),

        .op1_i                  (exe_op1_i),
        .op2_i                  (exe_op2_i),
        .op3_i                  (exe_op3_i),

        .alu_sel_i              (exe_alu_sel_i),
        .alu_sub_flag_i         (exe_alu_sub_flag_i),
        .alu_word_flag_i        (exe_alu_word_flag_i),
        .alu_symbol_flag_i      (exe_alu_symbol_flag_i),

        .transfer_en_i          (exe_transfer_en_i),
        .transfer_sel_i         (exe_transfer_sel_i),

        // .csr_en_i               (exe_csr_en_i),
        .csr_sel_i              (exe_csr_sel_i),

        .mem_load_en_i          (exe_mem_load_en_i),
        .mem_store_en_i         (exe_mem_store_en_i),
        .mem_sel_i              (exe_mem_sel_i),

        .rd_sel_i               (exe_rd_sel_i),

        .exception_type_from_wb_i   (wb_exception_type_o),
        .exception_type_from_mem_i  (mem_exception_type_o),
        .exception_type_i       (exe_exception_type_i),
        .valid_i                (exe_valid_i),

        .inst_addr_o            (exe_inst_addr_o),
        .inst_o                 (exe_inst_o),

        .csr_w_ena_o            (exe_csr_w_ena_o),
        .csr_w_addr_o           (exe_csr_w_addr_o),
        .csr_w_data_o           (exe_csr_w_data_o),

        .rd_w_ena_o             (exe_rd_w_ena_o),
        .rd_w_addr_o            (exe_rd_w_addr_o),
        .rd_w_data_o            (exe_rd_w_data_o),

        .mem_addr_o             (exe_mem_addr_o),
        .mem_w_data_o           (exe_mem_w_data_o),

        .transfer_flag_o        (exe_transfer_flag_o),
        .transfer_addr_o        (exe_transfer_addr_o),
    
        .mem_load_en_o          (exe_mem_load_en_o),
        .mem_store_en_o         (exe_mem_store_en_o),
        .mem_sel_o              (exe_mem_sel_o),

        .exception_type_o       (exe_exception_type_o),
        .valid_o                (exe_valid_o)
    );
    // mem stage
    exe_mem Exe_mem(
        .clk                    (clock),
        .rst                    (reset),

        .stall_i                (ctrl_stall_o[1]),
        .flush_i                (ctrl_flush_o[1]),

        .inst_addr_i            (exe_inst_addr_o),
        .inst_i                 (exe_inst_o),

        .csr_w_ena_i            (exe_csr_w_ena_o),
        .csr_w_addr_i           (exe_csr_w_addr_o),
        .csr_w_data_i           (exe_csr_w_data_o),

        .rd_w_ena_i             (exe_rd_w_ena_o),
        .rd_w_addr_i            (exe_rd_w_addr_o),
        .rd_w_data_i            (exe_rd_w_data_o),

        .mem_addr_i             (exe_mem_addr_o),
        .mem_w_data_i           (exe_mem_w_data_o),

        .mem_load_en_i          (exe_mem_load_en_o),
        .mem_store_en_i         (exe_mem_store_en_o),
        .mem_sel_i              (exe_mem_sel_o),

        .exception_type_i       (exe_exception_type_o),
        .valid_i                (exe_valid_o),

        .inst_addr_o            (mem_inst_addr_i),
        .inst_o                 (mem_inst_i),

        .csr_w_ena_o            (mem_csr_w_ena_i),
        .csr_w_addr_o           (mem_csr_w_addr_i),
        .csr_w_data_o           (mem_csr_w_data_i),

        .rd_w_ena_o             (mem_rd_w_ena_i),
        .rd_w_addr_o            (mem_rd_w_addr_i),
        .rd_w_data_o            (mem_rd_w_data_i),

        .mem_addr_o             (mem_mem_addr_i),
        .mem_w_data_o           (mem_mem_w_data_i),

        .mem_load_en_o          (mem_mem_load_en_i),
        .mem_store_en_o         (mem_mem_store_en_i),
        .mem_sel_o              (mem_mem_sel_i),

        .exception_type_o       (mem_exception_type_i),
        .valid_o                (mem_valid_i)
    );

    mem_stage Mem_stage(
        .inst_addr_i            (mem_inst_addr_i),
        .inst_i                 (mem_inst_i),

        .csr_w_ena_i            (mem_csr_w_ena_i),
        .csr_w_addr_i           (mem_csr_w_addr_i),
        .csr_w_data_i           (mem_csr_w_data_i),

        .rd_w_ena_i             (mem_rd_w_ena_i),
        .rd_w_addr_i            (mem_rd_w_addr_i),
        .rd_w_data_i            (mem_rd_w_data_i),

        .mem_addr_i             (mem_mem_addr_i),
        .mem_w_data_i           (mem_mem_w_data_i),

        .mem_r_data_i           (mem_mem_r_data_i),

        .mem_load_en_i          (mem_mem_load_en_i),
        .mem_store_en_i         (mem_mem_store_en_i),
        .mem_sel_i              (mem_mem_sel_i),

        .exception_type_from_wb_i(wb_exception_type_o),
        .exception_type_i       (mem_exception_type_i),
        .valid_i                (mem_valid_i),

        .inst_addr_o            (mem_inst_addr_o),
        .inst_o                 (mem_inst_o),

        .csr_w_ena_o            (mem_csr_w_ena_o),
        .csr_w_addr_o           (mem_csr_w_addr_o),
        .csr_w_data_o           (mem_csr_w_data_o),

        .rd_w_ena_o             (mem_rd_w_ena_o),
        .rd_w_addr_o            (mem_rd_w_addr_o),
        .rd_w_data_o            (mem_rd_w_data_o),
        
        .dram_w_mask_o          (mem_dram_w_mask_o),
        .dram_w_data_o          (mem_dram_w_data_o),
        .dram_w_en_o            (mem_dram_w_en_o),
        .dram_addr_o            (mem_dram_addr_o),
        .dram_rw_size_o         (mem_dram_rw_size_o),

        .dram_valid             (mem_dram_valid),
        .dram_ready             (mem_dram_ready),

        .stall_3_2_1_flag_o     (mem_stall_3_2_1_flag_o),

        .exception_type_o       (mem_exception_type_o),
        .valid_o                (mem_valid_o)
    );

    //wb stage
    mem_wb Mem_wb(
        .clk                    (clock),
        .rst                    (reset),

        .stall_i                (ctrl_stall_o[0]),
        .flush_i                (ctrl_flush_o[0]),

        .inst_addr_i            (mem_inst_addr_o),
        .inst_i                 (mem_inst_o),

        .csr_w_ena_i            (mem_csr_w_ena_o),
        .csr_w_addr_i           (mem_csr_w_addr_o),
        .csr_w_data_i           (mem_csr_w_data_o),

        .rd_w_ena_i             (mem_rd_w_ena_o),
        .rd_w_addr_i            (mem_rd_w_addr_o),
        .rd_w_data_i            (mem_rd_w_data_o),

        .exception_type_i       (mem_exception_type_o),
        .valid_i                (mem_valid_o),
        .skip_i                 (mem_skip_o),

        .inst_addr_o            (wb_inst_addr_i),
        .inst_o                 (wb_inst_i),

        .csr_w_ena_o            (wb_csr_w_ena_i),
        .csr_w_addr_o           (wb_csr_w_addr_i),
        .csr_w_data_o           (wb_csr_w_data_i),

        .rd_w_ena_o             (wb_rd_w_ena_i),
        .rd_w_addr_o            (wb_rd_w_addr_i),
        .rd_w_data_o            (wb_rd_w_data_i),

        .exception_type_o       (wb_exception_type_i),
        .valid_o                (wb_valid_i),
        .skip_o                 (wb_skip_i)
    );

    wb_stage Wb_stage(
        .inst_addr_i            (wb_inst_addr_i),
        .inst_i                 (wb_inst_i),

        .csr_w_ena_i            (wb_csr_w_ena_i),
        .csr_w_addr_i           (wb_csr_w_addr_i),
        .csr_w_data_i           (wb_csr_w_data_i),

        .rd_w_ena_i             (wb_rd_w_ena_i),
        .rd_w_addr_i            (wb_rd_w_addr_i),
        .rd_w_data_i            (wb_rd_w_data_i),

        .exception_type_i       (wb_exception_type_i),
        .valid_i                (wb_valid_i),

        .skip_i                 (wb_skip_i),

        .inst_addr_o            (wb_inst_addr_o),
        .inst_o                 (wb_inst_o),

        .csr_w_ena_o            (wb_csr_w_ena_o),
        .csr_w_addr_o           (wb_csr_w_addr_o),
        .csr_w_data_o           (wb_csr_w_data_o),

        .rd_w_ena_o             (wb_rd_w_ena_o),
        .rd_w_addr_o            (wb_rd_w_addr_o),
        .rd_w_data_o            (wb_rd_w_data_o),

        .exception_type_o       (wb_exception_type_o),
        .valid_o                (wb_valid_o),

        .skip_o                 (wb_skip_o)
    );

    wire [`REG_BUS] regs_diff[0 : 31];
    wire [2:0] trap_code_sim;
    assign trap_code_sim = (regs_diff[10] == 64'h0) ? 3'h0 : 3'h1;
    //regfile
    regfile Regfile(
        .clk                    (clock),
        .rst                    (reset),

        .r_addr1                (id_rs1_r_addr_o),
        .r_data1                (id_rs1_r_data_i),
        .r_ena1                 (id_rs1_r_ena_o),

        .r_addr2                (id_rs2_r_addr_o),
        .r_data2                (id_rs2_r_data_i),
        .r_ena2                 (id_rs2_r_ena_o),

        .w_ena                  (wb_rd_w_ena_o),
        .w_addr                 (wb_rd_w_addr_o),
        .w_data                 (wb_rd_w_data_o),
        //for trap
        .regs_o                 (regs_diff)
    );
    
    csr Csr(
        .clk                    (clock),
        .rst                    (reset),

        .timer_interrupt        (clint_timer_interrupt_o),

        .timer_interrupt_flag_o (csr_timer_interrupt_flag_o),
        
        .r_addr                 (id_csr_r_addr_o),
        .r_data                 (id_csr_r_data_i),
        .r_ena                  (id_csr_r_ena_o),

        .w_addr                 (wb_csr_w_addr_o),
        .w_data                 (wb_csr_w_data_o),
        .w_ena                  (wb_csr_w_ena_o),
        .exception_type         (wb_exception_type_o),
        .inst_addr              (wb_inst_addr_o),

        .transfer_flag          (csr_transfer_flag_o),
        .transfer_addr          (csr_transfer_addr_o),

        .mstatus_diff           (mstatus_diff),
        .sstatus_diff           (sstatus_diff),
        .mepc_diff              (mepc_diff),
        .mtvec_diff             (mtvec_diff),
        .mcause_diff            (mcause_diff),
        .mip_diff               (mip_diff),
        .mie_diff               (mie_diff),
        .mscratch_diff          (mscratch_diff),
        .exception_code_diff    (exception_code_wire)
    );
    wire [ 7: 0]                    mem_w_mask_o_real;
    wire [`RAM_DATA_WIDTH - 1: 0]   mem_w_data_o_real;
    wire                            mem_w_en_o_real;
    wire [`RAM_ADDR_WIDTH - 1: 0]   mem_addr_o_real;

    wire [`RAM_DATA_WIDTH - 1: 0]   clint_r_data;
    wire                            clint_valid;
    wire                            clint_ready;



    mem_filter mem_filter_sim(

        .dram_w_mask_i          (mem_dram_w_mask_o),
        .dram_w_data_i          (mem_dram_w_data_o),
        .dram_w_en_i            (mem_dram_w_en_o),
        .dram_r_data_o          (mem_mem_r_data_i),
        .dram_addr_i            (mem_dram_addr_o),
        .dram_valid_i           (mem_dram_valid),
        .dram_ready_o           (mem_dram_ready),

        .dram_w_mask_o          (mem_w_mask_o_real),
        .dram_w_data_o          (mem_w_data_o_real),
        .dram_w_en_o            (mem_w_en_o_real),
        .dram_addr_o            (mem_addr_o_real),

        .dram_r_data_i          (dram_rdata),
        .dram_valid_o           (dram_valid),
        .dram_ready_i           (dram_ready),

        .clint_r_data_i         (clint_r_data),
        .clint_valid_o          (clint_valid),
        .clint_ready_i          (clint_ready),

        .skip_o                 (mem_skip_o)
    );
    clint clint_sim(
        .clk                    (clock),
        .rst                    (reset),

        .clint_w_data_i         (mem_w_data_o_real),
        .clint_w_en_i           (mem_w_en_o_real),
        .clint_r_data_o         (clint_r_data),
        .clint_addr_i           (mem_addr_o_real),
        .clint_valid_i          (clint_valid),
        .clint_ready_o          (clint_ready),

        .timer_interrupt        (clint_timer_interrupt_o)
    );
    //////////////////////////////////////////////////////////////////////////////////////////////////

    //DifftestInstrCommit
    always @(posedge clock) begin
        if(reset == 1'b1)begin
            coreid_sim   <= 8'h0;
            index_sim    <= 8'h0;
            valid_sim    <= 1'h0;
            pc_sim       <= `ZERO_WORD;
            instr_sim    <= 32'h0;
            skip_sim     <= 1'h0;
            isRVC_sim    <= 1'h0;
            scFailed_sim <= 1'h0;
            wen_sim      <= 1'h0;
            wdest_sim    <= 5'h0;
            wdata_sim    <= `ZERO_WORD;
        end
        else begin
            coreid_sim   <= 8'h0;
            index_sim    <= 8'h0;
            valid_sim    <= wb_valid_o;
            // valid_sim    <= 1'b1;
            pc_sim       <= wb_inst_addr_o;
            instr_sim    <= wb_inst_o;
            skip_sim     <= wb_inst_o == 32'hb0002973 || wb_inst_o == 32'hb00024f3 ? 1'b1 : wb_skip_o;
            isRVC_sim    <= 1'b0;
            scFailed_sim <= 1'b0;
            wen_sim      <= wb_rd_w_ena_o;
            wdest_sim    <= wb_rd_w_addr_o;
            wdata_sim    <= wb_rd_w_data_o;
        end
    end
    // 打印
    always @(posedge clock) 
    begin
            if(wb_inst_o == 32'h7b)
            begin
                $write("%c", regs_diff[10][7:0]);
            end
    end
    DifftestInstrCommit DifftestInstrCommit_sim(
        .clock                  (clock),
        .coreid                 (coreid_sim),
        .index                  (index_sim),
        .valid                  (valid_sim),
        .pc                     (pc_sim),
        .instr                  (instr_sim),
        .special                (0),
        .skip                   (skip_sim),
        .isRVC                  (isRVC_sim),
        .scFailed               (scFailed_sim),
        .wen                    (wen_sim),
        .wdest                  (wdest_sim),
        .wdata                  (wdata_sim)
    );

    always @(posedge clock) begin
        if(reset == 1'b1)begin
            exception_code <= `ZERO_WORD;
        end
        else begin
            exception_code <= exception_code_wire;
        end
    end
    wire[31: 0] event_intrNO = exception_code[63] == 1'b1 ? exception_code[31:0] : 32'h0;
    wire[31: 0] enent_cause  = exception_code[63] == 1'b0 ? exception_code[31:0] : 32'h0;
    DifftestArchEvent DifftestArchEvent_sim(
        .clock                  (clock),
        .coreid                 (0),
        .intrNO                 (event_intrNO),
        .cause                  (enent_cause),
        .exceptionPC            (mepc_diff),
        .exceptionInst          (instr_sim)
    );

    DifftestArchIntRegState DifftestArchIntRegState (
        .clock                  (clock),
        .coreid                 (0),
        .gpr_0                  (regs_diff[0]),
        .gpr_1                  (regs_diff[1]),
        .gpr_2                  (regs_diff[2]),
        .gpr_3                  (regs_diff[3]),
        .gpr_4                  (regs_diff[4]),
        .gpr_5                  (regs_diff[5]),
        .gpr_6                  (regs_diff[6]),
        .gpr_7                  (regs_diff[7]),
        .gpr_8                  (regs_diff[8]),
        .gpr_9                  (regs_diff[9]),
        .gpr_10                 (regs_diff[10]),
        .gpr_11                 (regs_diff[11]),
        .gpr_12                 (regs_diff[12]),
        .gpr_13                 (regs_diff[13]),
        .gpr_14                 (regs_diff[14]),
        .gpr_15                 (regs_diff[15]),
        .gpr_16                 (regs_diff[16]),
        .gpr_17                 (regs_diff[17]),
        .gpr_18                 (regs_diff[18]),
        .gpr_19                 (regs_diff[19]),
        .gpr_20                 (regs_diff[20]),
        .gpr_21                 (regs_diff[21]),
        .gpr_22                 (regs_diff[22]),
        .gpr_23                 (regs_diff[23]),
        .gpr_24                 (regs_diff[24]),
        .gpr_25                 (regs_diff[25]),
        .gpr_26                 (regs_diff[26]),
        .gpr_27                 (regs_diff[27]),
        .gpr_28                 (regs_diff[28]),
        .gpr_29                 (regs_diff[29]),
        .gpr_30                 (regs_diff[30]),
        .gpr_31                 (regs_diff[31])
    );
    reg [63:0] cycleCnt;
    reg [63:0] instrCnt;
    always @(posedge clock) begin
        if(reset == 1'b1)begin
            cycleCnt <= 64'h0;
            instrCnt <= 64'h0;
        end
        else begin
            cycleCnt <= cycleCnt + 1;
            instrCnt <= instrCnt + wb_valid_o;
        end
    end 
    DifftestTrapEvent DifftestTrapEvent_sim(
        .clock                  (clock),
        .coreid                 (coreid_sim),
        .valid                  (instr_sim == 32'h0000_006b),
        .code                   (trap_code_sim),
        .pc                     (pc_sim),
        .cycleCnt               (cycleCnt),
        .instrCnt               (instrCnt)
    ); 
    DifftestCSRState DifftestCSRState_sim(
        .clock                  (clock),
        .coreid                 (0),
        .priviledgeMode         (`RISCV_PRIV_MODE_M),
        .mstatus                (mstatus_diff),
        .sstatus                (sstatus_diff),
        .mepc                   (mepc_diff),
        .sepc                   (0),
        .mtval                  (0),
        .stval                  (0),
        .mtvec                  (mtvec_diff),
        .stvec                  (0),
        .mcause                 (mcause_diff),
        .scause                 (0),
        .satp                   (0),
        .mip                    (mip_diff),
        .mie                    (mie_diff),
        .mscratch               (mscratch_diff),
        .sscratch               (0),
        .mideleg                (0),
        .medeleg                (0)
    );
    DifftestArchFpRegState DifftestArchFpRegState(
        .clock                  (clock),
        .coreid                 (0),
        .fpr_0                  (0),
        .fpr_1                  (0),
        .fpr_2                  (0),
        .fpr_3                  (0),
        .fpr_4                  (0),
        .fpr_5                  (0),
        .fpr_6                  (0),
        .fpr_7                  (0),
        .fpr_8                  (0),
        .fpr_9                  (0),
        .fpr_10                 (0),
        .fpr_11                 (0),
        .fpr_12                 (0),
        .fpr_13                 (0),
        .fpr_14                 (0),
        .fpr_15                 (0),
        .fpr_16                 (0),
        .fpr_17                 (0),
        .fpr_18                 (0),
        .fpr_19                 (0),
        .fpr_20                 (0),
        .fpr_21                 (0),
        .fpr_22                 (0),
        .fpr_23                 (0),
        .fpr_24                 (0),
        .fpr_25                 (0),
        .fpr_26                 (0),
        .fpr_27                 (0),
        .fpr_28                 (0),
        .fpr_29                 (0),
        .fpr_30                 (0),
        .fpr_31                 (0)
    );

    assign dram_wen     = mem_w_en_o_real;
    assign dram_addr    = mem_addr_o_real;
    assign dram_wdata   = mem_w_data_o_real;
    assign dram_wmask   = mem_w_mask_o_real;
    assign dram_rw_size = mem_dram_rw_size_o;
endmodule
